package com.xand.bt.terminal.main;

import java.awt.Frame;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.xand.bt.terminal.common.api.MarketConnector;
import com.xand.bt.terminal.common.util.FileHelper;
import com.xand.bt.terminal.dispatcher.MarketDepthDispatcher;
import com.xand.bt.terminal.market.ConnectorMarketStore;
import com.xand.bt.terminal.market.MarketReference;
import com.xand.bt.terminal.market.MarketStore;
import com.xand.bt.terminal.ui.MainWindow;
import com.xand.bt.terminal.ui.depth.MarketDepthTableController;
import com.xand.bt.terminal.ui.logger.LoggerTableController;
import com.xand.bt.terminal.util.BitcoinTerminalConst;
import com.xand.bt.terminal.util.ConfigurationReader;

public class BitcoinTerminal {

	private static final String WORKING_DIR = "/home/xand/dev/workspace_w_window_builder/xand-bt-terminal-work/working_dir";
	
	private static BitcoinTerminal instance;

	private String workingDir;
	
	private MainWindow mainWindow;
	
	private MarketDepthDispatcher marketDepthDispatcher;
	
	private MarketInfoUpdaterThread marketInfoUpdater;
	
	private BitcoinTerminalConfiguration config;
	
	private List<MarketConnector> connectors;
	
	private MarketStore marketStore;
	
	public static BitcoinTerminal getInstance() {
		
		if(instance == null) {
			instance = new BitcoinTerminal();
			instance.initApp();
		}
		
		return instance;
		
	}
	
	private void initApp() {
		this.workingDir = WORKING_DIR;
		
		Properties configProperties = FileHelper.readPropertiesFile(
				this.workingDir + File.separator + BitcoinTerminalConst.TERMINAL_CONFIG_DIR 
				+ File.separator + BitcoinTerminalConst.TERMINAL_CONFIG_FILE);
		
		if(configProperties == null) {
			
			// TODO: PROCESS
			
		} else {
			
			this.marketStore = new MarketStore();
			
			this.config = ConfigurationReader.buildBitcoinTerminalConfiguration(configProperties);
			
			this.mainWindow = new MainWindow();
			
			this.marketDepthDispatcher = new MarketDepthDispatcher();
			
			this.marketInfoUpdater = new MarketInfoUpdaterThread(this.marketStore);
			
			this.connectors = new ArrayList<MarketConnector>();
			
			// setup connectors
			List<String> connectors = this.config.getConnectorClasses();
			for(String connector : connectors) {
				
				try {
					
					Class<?> clazz = Class.forName(connector);
					MarketConnector marketConnector = (MarketConnector)clazz.newInstance();
					
					Properties properties = this.config.getConnectorProperties(connector);
					
					marketConnector.setConfiguration(properties);
					marketConnector.init();
					
					this.marketInfoUpdater.addMarketConnector(marketConnector);
					this.connectors.add(marketConnector);
					
					this.marketStore.addMarketDepthTableController(
							marketConnector.getClass().getCanonicalName(), 
							mainWindow.getMarketDepthTable().getController());
					
					this.marketStore.createConnectorMarketStore(connector);
					
					List<String> references = marketConnector.getMarketReferences();
					for(String reference : references) {
						MarketReference marketReference = new MarketReference(reference);
						ConnectorMarketStore connectorMarketStore = this.marketStore.getConnectorMarketStore(connector);
						connectorMarketStore.addMarketReference(marketReference);
					}
					
				}catch(ClassNotFoundException e) {
					throw new RuntimeException(e);
				}catch(IllegalAccessException e) {
					throw new RuntimeException(e);
				}catch(InstantiationException e) {
					throw new RuntimeException(e);
				}
				
			}
			
			this.marketInfoUpdater.start();
			
		}
	}
	
	public MarketDepthTableController getMarketDepthTableController() {
		return this.mainWindow.getMarketDepthTable().getController();
	}
	
	public LoggerTableController getLoggerTableController() {
		return this.mainWindow.getLoggerTableDisplay().getController();
	}
	
	public MarketDepthDispatcher getMarketDepthDispatcher() {
		return this.marketDepthDispatcher;
	}
	
	public void exit() {
		
		for(MarketConnector connector : this.connectors) {
			connector.stop();
		}
		
		this.marketInfoUpdater.stop();
		
		Frame[] frames = Frame.getFrames();
		for(Frame frame : frames) {
			
			frame.dispose();
			
		}
	}
	
}
